<?php
/* OpenBIBLIO -- A library administration web interface
 * Copyright (C) 2011-2012 Laurent Luyssen   <big.lol13@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

require_once "db.inc";
require_once 'functions.inc';

class SearchFilter {
	const TYPE_EQUAL = 0;
	const TYPE_LIKE  = 1;
	public  $column = '';
	public  $value  = '';
	public  $type   = self::TYPE_EQUAL;
	
	public function __construct($a_column, $a_value, $a_type = self::TYPE_EQUAL) {
		$this->column = $a_column;
		$this->value  = $a_value;
		$this->type   = $a_type;
	}
	
	public function getSQL($table) {
		$cond = '';
		$tmp = explode(' ', trim($this->value));
		foreach ($tmp as $word) {
			if (empty($word))
				continue;
			if (!empty($cond))
				$cond .= " AND ";
			if ($this->type == self::TYPE_EQUAL) {
				if (is_numeric($word))
					$cond .= $table.".".$this->column." = ".$word;
				else
					$cond .= $table.".".$this->column." = '".mysql_real_escape_string ($word)."'";
			}
			elseif ($this->type == self::TYPE_LIKE) {
				$cond .= $table.".".$this->column." like '%".mysql_real_escape_string($word)."%'";
			}				
		}
		return "(".$cond.")";
	}
}

class SearchDAO {
    protected static $instance = FALSE;
    protected static $db = FALSE;
    protected static $allowedCols = FALSE;
	protected static $objName = '';
	
    protected $primarySortOrder = DBSortOrder::asc;
    protected $secondarySortOrder = DBSortOrder::asc;
    protected $primarySortCol = 'auteur';
    protected $secondarySortCol = 'nom';
    protected $filters = array();
    protected $includeLoaned = TRUE;
    protected $includeNotLoaned = TRUE;
    protected $startRow = 0;
    protected $rowsPerPage = 10;
    protected $result = FALSE; // Result of the search query
    protected $foundRows = 0; // Total number of rows found
    protected $qry = ''; // Last qury performed, for debugging
	
    private function __construct() {
    }
    
	protected static function init() {
		self::$objName = 'searchObj';
		self::$allowedCols['id'] = _("Id");
		self::$allowedCols['ISBN'] = _("ISBN");
		self::$allowedCols['nom'] = _("Titre");
		self::$allowedCols['auteur'] = _("Auteur");
		self::$allowedCols['collection'] = _("Coll.");
		self::$allowedCols['edition'] = _("Edition");
		self::$allowedCols['date_ed'] = _("Date");
		self::$allowedCols['genre_ID'] = '';
		self::$allowedCols['genre'] = _("Genre");
		self::$allowedCols['etat_ID'] = "";
		self::$allowedCols['etat'] = _("Etat");
		self::$allowedCols['location_ID'] = '';
		self::$allowedCols['location'] = _("Location");
		self::$allowedCols['local'] = _("Local");
		self::$allowedCols['biblio'] = _("Biblioth&egrave;que");
		self::$allowedCols['rangee'] = _("Rang&eacute;e");
		self::$allowedCols['motclefs'] = _("Mots clefs");
		self::$allowedCols['resume'] = _("R&eacute;sum&eacute;");
		self::$allowedCols['numero'] = _("Num&eacute;ro");
	}
	
	public static function getAllowedCols() {
		if (!self::$allowedCols)
			self::init();
		return self::$allowedCols;
	}
	
	/**
	 *
	 * @param String $db_name 
	 * @return boolean
	 */
	public static function isAllowedCol($db_name) {
		if (!self::$allowedCols)
			self::init();
		if (isset(self::$allowedCols[$db_name]))
			return TRUE;
		else
			return FALSE;
	}
    /**
     * @return SearchDAO
     */
    public static function getInstance() {
		global $db;	
		if (!self::$allowedCols)
			self::init ();
		if (self::$instance == FALSE) {
			if (isset($_SESSION[self::$objName]))
				$s = unserialize ($_SESSION[self::$objName]);
			else {  
				$s = new SearchDAO ();
				$s->saveToSession();
			}
			self::$instance = $s;
			self::$db = $db;
		}
		return self::$instance;
    }
    
    public function saveToSession() {
		if ($this->result) {
			mysql_free_result($this->result);
			$this->result = FALSE;
		}			
		$_SESSION[self::$objName] = serialize($this);
    }
    
    public function setSortOrder($order) {
		if ( ($order == DBSortOrder::asc) || ($order == DBSortOrder::desc) )
			$this->primarySortOrder = $order;
    }
    
    public function getPrimarySortOrder() {
		return $this->primarySortOrder;
    }
	
	public function getPrimarySortColumn() {
		return $this->primarySortCol;
	}
    
    public function getSecondarySortOrder() {
		return $this->secondarySortOrder;
    }
	
	public function getSecondarySortColumn () {
		return $this->secondarySortCol;
	}
    
    public function setSortCol($col) {
		if (!self::isAllowedCol($col))
			return;
		// If sort colums is the same, just switch sort order
		if ($col == $this->primarySortCol) {
			if ($this->primarySortOrder == DBSortOrder::asc)
				$this->setSortOrder (DBSortOrder::desc);
			else
				$this->setSortOrder (DBSortOrder::asc);
			return;
		}
		$this->secondarySortCol = $this->primarySortCol;
		$this->secondarySortOrder = $this->primarySortOrder;
		$this->primarySortCol = $col;
    }
    
    public function resetFilters() {
		unset($this->filter);
		$this->filters = array();
    }
    
    public function addFilter($field, $value, $type = SearchFilter::TYPE_EQUAL) {
		if (!self::isAllowedCol($field))
			return;
		if (empty($value)) 
			$this->removeFilter($field);
		else
			$this->filters[$field] = new SearchFilter($field, $value, $type);
    }
    
	public function removeFilter($field) {
		if (isset($this->filters[$field]))
			unset($this->filters[$field]);
	}
	
	public function getFilter($field, $asObject = FALSE) {
		if (isset($this->filters[$field]))
			if ($asObject)
				return $this->filters[$field];
			else
				return $this->filters[$field]->value;
		else 
			return FALSE;
	}
	
	public function setIncludeLoaned($inc) {
		$this->includeLoaned = $inc;
	}
	
	public function getIncludeLoaned() {
		return $this->includeLoaned;
	}
	
	public function setIncludeNotLoaned($inc) {
		$this->includeNotLoaned = $inc;
	}
	
	public function getIncludeNotLoaned() {
		return $this->includeNotLoaned;
	}
	
	private function buildQuery($limit = TRUE, $withKeywords = FALSE, $withSummary = FALSE) {
		$req  = "SELECT SQL_CALC_FOUND_ROWS p2.emprunteur,";
		$req .= " l.id AS id, l.nom AS nom, l.auteur AS auteur,";
		$req .= " l.ISBN as ISBN, l.location_ID AS location_ID,";
		$req .= " l.edition AS edition, l.date_ed AS date_ed,";
		$req .= " l.collection AS collection, l.del, l.num AS numero,";
		$req .= " l.cover_url AS cover_url,";
		$req .= " loc.local, loc.biblio, loc.rangee,";
		if ($withKeywords)
			$req .= " l.motclefs,";
		if ($withSummary)
			$req .= " l.resume,";
		$req .= " g.genre AS genre, e.etat AS etat";
		$req .= " FROM livres l";
		$req .= " LEFT OUTER JOIN prets2 p2 ON l.id = p2.livre_id AND p2.date_in IS NULL";
		$req .= " JOIN locations loc ON l.location_ID = loc.id";
		$req .= " JOIN genres g ON l.genre_ID = g.id";
		$req .= " JOIN etats e ON l.etat_ID = e.id";
		$req .= " WHERE l.del=0"; //  do no list deleted books
		if ($this->includeLoaned && !$this->includeNotLoaned)
			$req .= " AND p2.emprunteur IS NOT NULL";
		if (!$this->includeLoaned && $this->includeNotLoaned)
			$req .= " AND p2.emprunteur IS NULL";
		
		foreach ($this->filters as $filter) {
			if (empty($filter->value))
				continue;
			/*
			 * Logical operator between filters is AND
			 * If a filter is composed of several words, 
			 * logical operator between words is AND
			 */
			$cond = $filter->getSQL('l');
			if (!empty($cond))
				$req .= " AND ".$cond;
		}
		$req .= ' ORDER BY '.$this->primarySortCol.' '.$this->primarySortOrder;
		$req .= ', '.$this->secondarySortCol.' '.$this->secondarySortOrder;
		$req .= ', l.id asc';
		if ($limit)
			$req .= ' LIMIT '.$this->startRow.', '.$this->rowsPerPage;
		$this->qry = $req;
		return $req;
	}
	
	public function doSearch($limit = TRUE, $withKeywords = FALSE, $withSummary = FALSE) {
		$this->foundRows = 0;
		$req = $this->buildQuery($limit, $withKeywords, $withSummary);
		$this->result = biblio_db_query($req, self::$db);
		if ($this->result === FALSE)
			return FALSE;
		$res = biblio_db_query("SELECT FOUND_ROWS() AS `found_rows`", self::$db);
		if ($res === FALSE)
			return FALSE;
		$row = biblio_db_fetch_array($res);
		$this->foundRows = $row['found_rows'];
		return TRUE;
    }
    
    public function getRow() {
		if ($this->result === FALSE)
			return FALSE;
		$row = biblio_db_fetch_array($this->result);
		if ($row)
			$row['location'] = get_location_string($row['local'], $row['biblio'], $row['rangee']);
		return $row;
    }
    
    public function setRowsPerPage($nbRows) {
		$this->rowsPerPage = $nbRows;
    }
    
    public function getRowsPerPage() {
		return $this->rowsPerPage;
    }
    
    public function setStartRow($rowNum) {
		$this->startRow = $rowNum;
    }
    
    public function getStartRow() {
		return $this->startRow;
    }
    
    public function getFoundRowCount() {
		return $this->foundRows;
    }
	
	public function getQuery() {
		return $this->qry;
	}
}

?>
